﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LearnMAUI2.Models;
using LearnMAUI2.Services;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using TheSalLab.MauiInfiniteScrolling;

namespace LearnMAUI2.ViewModels;

//搜索结果页，支持无限滚动 
public class ResultPageViewModel : ObservableObject
{
    private readonly IPoetryStorage _poetryStorage;

    private readonly IContentNavigationService _contentNavigationService;

    //一次获取的数量
    public const int PageSize = 20;
    //提示信息
    public const string LoadingData = "Loading data...";
    public const string NoMatchedData = "No matched data";
    public const string NoMoreData = "No more data";

    private bool _canLoadMore;
    //状态
    private string _status;
    public string Status
    {
        get => _status;
        set => SetProperty(ref _status, value);
    }

    //通过一个可绑定条件接受搜索条件
    private Expression<Func<Poetry, bool>> _where;
    public Expression<Func<Poetry, bool>> Where
    {
        get => _where; 
        //借助SetProperty的原理，SetProperty会比较前后的值，如果当前值和旧值不同，则修改并触发通知，同时还会返回一个bool=true，借助这个赋值给_canLoadMore就可以了
        set => _canLoadMore = SetProperty(ref _where, value);
    }

    //无限滚动，类似于ObservableCollection<T>，但额外还带有一个无限滚动功能
    public MauiInfiniteScrollCollection<Poetry> Poetries { get; }

    public ResultPageViewModel(IPoetryStorage poetryStorage, IContentNavigationService contentNavigationService)
    {
        //[TODO]
        Where = Expression.Lambda<Func<Poetry, bool>>(Expression.Constant(true), Expression.Parameter(typeof(Poetry), "p"));
        //Initialize
        //注意不能在构造函数中调用异步函数，即不能在构造函数中对异步函数使用Wait(),构造函数始终是同步执行，容易造成死锁，即卡在这里不会再继续往下
        //poetryStorage.InitializeAsync().Start();

        _poetryStorage = poetryStorage;
        Poetries = new MauiInfiniteScrollCollection<Poetry>
        {
            //判断是否到头，true表示到头
            OnCanLoadMore = () => _canLoadMore,//如果为true，就触发OnLoadMore
            //加载数据，本次新加入的数据，它是一个异步函数
            OnLoadMore = async () =>
            {
                Status = LoadingData;
                //注意这里的局部变量poetries是一个IEnumerable<T>，因此无法ToLength,Count等方法，并且一旦取出就无法再用，所以需要ToList一下
                var poetries = (await poetryStorage.GetPoetriesAsync(Where, Poetries.Count(), PageSize)).ToList();
                //当载入数据后，就应该清除状态
                Status = string.Empty;
                if (poetries.Count < PageSize)
                {
                    Status = NoMoreData;
                    _canLoadMore = false;
                }
                //如果查不出来并且原来的集合也为空，表示没有任何数据
                if (poetries.Count == 0 && Poetries.Count == 0)
                {
                    Status = NoMatchedData;
                    _canLoadMore = false;
                }
                return poetries;
            }
        };
        _lazyCommand = new Lazy<AsyncRelayCommand>(() => new AsyncRelayCommand(NavigatedToCommandFunction));
        _contentNavigationService = contentNavigationService;
    }

    //当导航到该页面时就第一次加载数据
    private RelayCommand _navigatedToCommand;

    //注意Command的Execute方法是一个多线程执行的方法，最后将其内部逻辑剥离以更好的单元测试
    public RelayCommand NavigatedToCommand => _navigatedToCommand ??= new RelayCommand(async () =>
    {
        await _poetryStorage.InitializeAsync();
        await NavigatedToCommandFunction();
    });

    //TODO
    private RelayCommand _testCommand;
    //TODO 仅用于测试是否能够传参
    public RelayCommand TestCommand => _testCommand ??= new RelayCommand(async () =>
    {
        await _contentNavigationService.NavigateToAsync(ContentNavigationConstant.DetailPage, Poetries[0]);
    });

    public async Task NavigatedToCommandFunction()
    {
        //清理现有数据
        Poetries.Clear();
        await Poetries.LoadMoreAsync();
    }

    private Lazy<AsyncRelayCommand> _lazyCommand;
    public AsyncRelayCommand lazyCommand => _lazyCommand.Value;

    //带参命令
    private RelayCommand<Poetry> _poetryTappedCommand;

    //targetPoetry就是对应的参数
    public RelayCommand<Poetry> PoetryTappedCommand => _poetryTappedCommand ??= new RelayCommand<Poetry>( async targetPoetry =>
    {
        await _contentNavigationService.NavigateToAsync(ContentNavigationConstant.DetailPage,targetPoetry);
    });
}
